<?php
class SDBUtils {
	private $sdb;
	private $items = null;
	public $verbose = false;
	
	public function __construct() {
		$this->sdb = new AmazonSDB();
	}
	
	public function notify($str) {
		if ($this->verbose === true) {
			echo "[VERBOSE] ";
			$trace = debug_backtrace();
			$caller = $trace[1];
			if (isset($caller["class"])) {
				echo $caller["class"] . "->";
			}
			if (isset($caller["function"])) {
				echo $caller["function"] . "()";
			}	
			echo " ($str)\n";
		}
	}
	
	/**
   * Resets internal variables 
   *
   * @return bool: method always returns true;
   */
	public function reset() {
		$this->items = null;
		return true;
	}
	
	/**
   * Checks to see if domain exists 
   *
   * @param string $domainSearch domain to search for
   * @return bool: true if exist, false if not
   */
	public function domainExist($domainSearch) {
		$domainList = $this->domainList();
		if (in_array($domainSearch, $domainList)) {
			return true;
		}
		return false;
	}
	
	/**
   * Returns a array of domains 
   *
   * @return array: list of domains
   */
	public function domainList() {
		$domains = $this->sdb->list_domains();
		$domainList = null;
		if ($domains->isOK()) {
			foreach ($domains->body->ListDomainsResult->DomainName as $domain) {
				$domainList[] = (string) $domain;
			}
		} else {
			$code = $res->body->Errors->Error->Code;
			$message = $res->body->Errors->Error->Message;
			throw new Exception (Errors::SDBUtils_MESG_FAILED_FETCH_DOMAIN_LIST . ": ($code | $message)", Errors::SDBUtils_CODE_FAILED_FETCH_DOMAIN_LIST);
		}
		return $domainList; 
	}
	
	/**
   * Creates a domain 
   *
   * @param string $domain Domain to create
   * @return bool: true if successful
   */
	public function domainCreate($domain) {
		$res = $this->sdb->create_domain($domain);
		if (!$res->isOK()) {
			$code = $res->body->Errors->Error->Code;
			$message = $res->body->Errors->Error->Message;
			throw new Exception (Errors::SDBUtils_MESG_FAILED_CREATE_DOMAIN . ": ($code | $message)", Errors::SDBUtils_CODE_FAILED_CREATE_DOMAIN);
		}
		return true;
	}
	
	/**
   * Deletes a domain 
   *
   * @param string $domain Domain to delete
   * @return bool: true if successful
   */
	public function domainDelete($domain) {
		$res = $this->sdb->delete_domain($domain);
		if (!$res->isOK()) {
			$code = $res->body->Errors->Error->Code;
			$message = $res->body->Errors->Error->Message;
			throw new Exception (Errors::SDBUtils_MESG_FAILED_DELETE_DOMAIN . ": ($code | $message)", Errors::SDBUtils_CODE_FAILED_DELETE_DOMAIN);
		}
		return true;
	}	

	/**
   * Wrapper method to get all items in a domain 
   *
   * @param string $domain Domain to query
   * @return array: array of items
   */
	public function domainGetAll($domain) {
		$ret = $this->__domainGetAll($domain);
		$this->reset();
		return $ret;
	}
	
	/**
   * Queries all items in a domain; is aware of SDB nextToken 
   *
   * @param string $domain Domain to query
   * @param string $nextToken Next token to query for remainer of query
   * @return array: array of items
   */
	private function __domainGetAll($domain, $nextToken = null) {
		if ($this->domainExist($domain)) {
			$attribList = null;
			$optsArray = null;
			if (!is_null($nextToken)) {
				$optsArray = array("NextToken" => $nextToken);
			}
			$selectAll = $this->sdb->select("SELECT * FROM `$domain`", $optsArray);
			if ($selectAll->isOK()) {
				foreach ($selectAll->body->SelectResult->Item as $item) {
					$this->items[(string) $item->Name]["uuid"] = (string) $item->Name; 
					foreach ($item->Attribute as $attrib) {
						$this->items[(string) $item->Name][(string) $attrib->Name] = (string) $attrib->Value;
					}
				}
			if (isset($selectAll->body->SelectResult->NextToken)) {
				$this->__domainGetAll($domain, (string) $selectAll->body->SelectResult->NextToken);
			}
			} else {
				$code = $res->body->Errors->Error->Code;
				$message = $res->body->Errors->Error->Message;
				throw new Exception (Errors::SDBUtils_MESG_FAILED_DOMAIN_GET_ALL . ": ($code | $message)", Errors::SDBUtils_CODE_FAILED_DELETE_DOMAIN);
			}
			return $this->items;
		} else {
			throw new Exception(Errors::SDBUtils_MESG_DOMAIN_NOT_EXIST . "($domain)", Errors::SDBUtils_CODE_DOMAIN_NOT_EXIST);
		}
	}
	
	public function domainSelect($select) {
		$ret = $this->__domainSelect($select);
		$this->reset();
		return $ret;
	}
	
	public function __domainSelect($select, $nextToken = null) {
		$attribList = null;
		if (!is_null($nextToken)) {
			$selectAll = $this->sdb->select($select, array("NextToken" => $nextToken));
		} else {
			$selectAll = $this->sdb->select($select);
		}
		if ($selectAll->isOK()) {
			foreach ($selectAll->body->SelectResult->Item as $item) {
				$this->items[(string) $item->Name]["uuid"] = (string) $item->Name; 
				foreach ($item->Attribute as $attrib) {
					$this->items[(string) $item->Name][(string) $attrib->Name] = (string) $attrib->Value;
				}
			}
		} else {
			$code = $selectAll->body->Errors->Error->Code;
			$message = $selectAll->body->Errors->Error->Message;
			throw new Exception (Errors::SDBUtils_MESG_DOMAIN_SELECT_FAILED . ": ($code | $message)", Errors::SDBUtils_CODE_DOMAIN_SELECT_FAILED);
		}
		$checkNextToken = isset($selectAll->body->SelectResult->NextToken) ? (string) $selectAll->body->SelectResult->NextToken : null;
		if (!is_null($checkNextToken)) {
			$this->__domainSelect($select, $checkNextToken);
		}
		return $this->items;
	}
	
	public function itemPut($domain, $item, $keypairs, $replace = false) {
		if ($this->domainExist($domain)) {
			$res = $this->sdb->put_attributes($domain, $item, $keypairs, $replace);
			if (!$res->isOK()) {
				$code = $res->body->Errors->Error->Code;
				$message = $res->body->Errors->Error->Message;
				throw new Exception (Errors::SDBUtils_MESG_ITEM_PUT_FAILED . ": ($code | $message)", Errors::SDBUtils_CODE_ITEM_PUT_FAILED);
			}
		} else {
			throw new Exception(Errors::SDBUtils_MESG_DOMAIN_NOT_EXIST . "($domain)", Errors::SDBUtils_CODE_DOMAIN_NOT_EXIST);
		}
		return true;
	}
	
	public function itemsBatchPut($domain, $items, $replace = false) {
		if ($this->domainExist($domain)) {
			foreach (array_chunk($items, 25, true) as $itemChunk) {
				$res = $this->sdb->batch_put_attributes($domain, $itemChunk, $replace);
				if (!$res->isOK()) {
					$code = $res->body->Errors->Error->Code;
					$message = $res->body->Errors->Error->Message;
					throw new Exception (Errors::SDBUtils_MESG_ITEM_BATCH_PUT_FAILED . ": ($code | $message)", Errors::SDBUtils_CODE_ITEM_BATCH_PUT_FAILED);
				}
			}
		} else {
			throw new Exception(Errors::SDBUtils_MESG_DOMAIN_NOT_EXIST . "($domain)", Errors::SDBUtils_CODE_DOMAIN_NOT_EXIST);
		}		
		return true;
	}
	
	public function itemGet($domain, $itemRequest, $attrib = null) {
		if ($this->domainExist($domain)) {
			$res = $this->sdb->get_attributes($domain, $itemRequest, $attrib);
			if ($res->isOK()) {
				$item = null;
				foreach ($res->body->GetAttributesResult->Attribute as $itemObject) {
					$item[(string)$itemObject->Name] = (string)$itemObject->Value; 
				}
				if (is_null($item)) {
					return false;
				}
				$item["uuid"] = $itemRequest;
				return $item;
			} else {
				$code = $res->body->Errors->Error->Code;
				$message = $res->body->Errors->Error->Message;
				throw new Exception (Errors::SDBUtils_MESG_ITEM_GET_FAILED . ": ($code | $message)", Errors::SDBUtils_CODE_ITEM_GET_FAILED);
			}
		} else {
			throw new Exception(Errors::SDBUtils_MESG_DOMAIN_NOT_EXIST . "($domain)", Errors::SDBUtils_CODE_DOMAIN_NOT_EXIST);
		}
	}
	
	public function itemDelete ($domain, $item) {
		if ($this->domainExist($domain)) {
			$res = $this->sdb->delete_attributes($domain, $item);
			if (!$res->isOK()) {
				$code = $res->body->Errors->Error->Code;
				$message = $res->body->Errors->Error->Message;
				throw new Exception (Errors::SDBUtils_MESG_ITEM_DELETE_FAILED . ": ($code | $message: domain($domain) item($item))", Errors::SDBUtils_CODE_ITEM_DELETE_FAILED);
			}
			return true;
		} else {
			throw new Exception(Errors::SDBUtils_MESG_DOMAIN_NOT_EXIST . "($domain)", Errors::SDBUtils_CODE_DOMAIN_NOT_EXIST);
		}
	}
	
	public function itemExist($domain, $item) {
		if ($this->domainExist($domain)) {
			$res = $this->sdb->get_attributes($domain, $item);
			if ($res->isOK()) {
				if (count($res->body->GetAttributesResult->Attribute) > 0) {
					return true;
				}
				return false;
			} else {
				$code = $res->body->Errors->Error->Code;
				$message = $res->body->Errors->Error->Message;
				throw new Exception (Errors::SDBUtils_MESG_ITEM_EXIST_FAILED . ": ($code | $message)", Errors::SDBUtils_CODE_ITEM_EXIST_FAILED);
			}
		} else {
			throw new Exception(Errors::SDBUtils_MESG_DOMAIN_NOT_EXIST . "($domain)", Errors::SDBUtils_CODE_DOMAIN_NOT_EXIST);
		}
	}
}
?>